#include "gralaby.hpp"
#include "../score/score.hpp"

#include <fstream>
#include <iostream>
#include <cmath>

Gralaby::Gralaby() {
	map = NULL;
}

Gralaby::~Gralaby() {

}

void Gralaby::init(Engine *engine) {
	// load map
	std::ifstream mapFile("data/gralaby/laby.txt");
	
	mapFile >> mapWidth >> mapHeight;
	map = new int[mapWidth * mapHeight];
	
	for(int j = 0; j < mapHeight; j++)
		for(int i = 0; i < mapWidth; i++)
			mapFile >> map[j * mapWidth + i];
	
	mapFile.close();
	
	// init players
	for(std::map<int, Player>::iterator iPlayer = engine->players.begin(); iPlayer != engine->players.end(); iPlayer++) {
		int index = (*iPlayer).first;
		gralabbers[index].sprite.SetCenter(sf::Vector2f(16.f, 16.f));
		gralabbers[index].sprite.SetPosition(sf::Vector2f(16.f, 48.f));
		gralabbers[index].sprite.SetImage(engine->getImage("data/gralaby/sprite.png"));
		gralabbers[index].sprite.SetColor(engine->players[index].color);
		
		gralabbers[index].name.SetText((*iPlayer).second.name);
		gralabbers[index].name.SetPosition(sf::Vector2f(0.f, 0.f));
		gralabbers[index].name.SetColor(sf::Color(255, 255, 255, 255));
		gralabbers[index].name.SetFont(engine->getFont("data/fonts/BELIEVER.TTF"));
		gralabbers[index].name.SetSize(16.f);
	}
	
	background.SetImage(engine->getImage("data/gralaby/background.png"));
	
	// reset clock
	clock.Reset();
}

void Gralaby::cleanup() {
	delete[] map;
}

void Gralaby::pause() {
	
}

void Gralaby::resume() {
	clock.Reset();
}

void Gralaby::processEvent(Engine *engine, PlayerEvent& event) {
	switch(event.type) {
		case PlayerEvent::Quit:
		{
			if(event.state)
				engine->changeState(Score::getSingleton());
			break;
		}
		default:
			break;
	}
}

int Gralaby::getMap(int x, int y) {
	if((x < 0) || (x >= mapWidth)) return 1;
	if((y < 0) || (y >= mapHeight)) return 1;
	
	return map[y * mapWidth + x];
}

void Gralaby::update(Engine *engine) {
	//const sf::Input& input = engine->window.GetInput();
	
	float time = clock.GetElapsedTime();
	clock.Reset();
	
	for(std::map<int, Gralabber>::iterator iGralabber = gralabbers.begin(); iGralabber != gralabbers.end(); iGralabber++) {
		int index = (*iGralabber).first;
		Gralabber& gralabber = gralabbers[(*iGralabber).first];
		
		sf::Vector2f goalMove;
		
		if((engine->players[index].actions[PlayerEvent::MoveLeft].state) && (!engine->players[index].actions[PlayerEvent::MoveRight].state))
			goalMove += sf::Vector2f(-200.f * time, 0.f);
		else if((engine->players[index].actions[PlayerEvent::MoveRight].state) && (!engine->players[index].actions[PlayerEvent::MoveLeft].state))
			goalMove += sf::Vector2f(200.f * time, 0.f);
		
		goalMove += sf::Vector2f(0.f, 200.f * time);
		
		float dist = sqrt(pow(goalMove.x, 2) + pow(goalMove.y, 2));
		
		bool blockX = false, blockY = false;
		for(int i = 1; (i < dist) && (!blockX || blockY); i++) {
			int x = int(gralabber.sprite.GetPosition().x + i * goalMove.x / dist);
			int y = int(gralabber.sprite.GetPosition().y + 16 + i * goalMove.y / dist);
			
			if(!blockY)
			if(getMap(int(gralabber.sprite.GetPosition().x / 32), y / 32)) {
				goalMove.y = goalMove.y * (i - 1) / dist;
				blockY = true;
			}
			
			if(!blockX)
			if(getMap(x / 32, int(gralabber.sprite.GetPosition().y  + 16) / 32)) {
				goalMove.x = goalMove.x * (i - 1) / dist;
				blockX = true;
			}
		}
				
		gralabber.sprite.Move(goalMove);
	}
}

void Gralaby::draw(Engine *engine) {
	engine->window.Draw(background);
	
	sf::Sprite wall;
	wall.SetImage(engine->getImage("data/gralaby/wall.png"));
	
	for(int j = 0; j < mapHeight; j++)
		for(int i = 0; i < mapWidth; i++)
			if(map[j * mapWidth + i] == 1) {
				wall.SetPosition(sf::Vector2f(i * 32, j * 32));
				engine->window.Draw(wall);
			}

	for(std::map<int, Player>::iterator iPlayer = engine->players.begin(); iPlayer != engine->players.end(); iPlayer++) {
		int index = (*iPlayer).first;
		engine->window.Draw(gralabbers[index].sprite);
		engine->window.Draw(gralabbers[index].name);
	}
}
